Les fonctions de fenêtre sont l'une des fonctionnalités les plus puissantes de SQL pour effectuer des calculs analytiques complexes. Contrairement aux fonctions d'agrégation qui regroupent plusieurs lignes en un seul résultat, les fonctions de fenêtre vous permettent d'effectuer des calculs sur un ensemble de lignes liées à la ligne actuelle—tout en préservant les lignes individuelles dans votre ensemble de résultats.
Cette leçon introduit les concepts fondamentaux des fonctions de fenêtre et démontre comment elles peuvent transformer vos capacités d'analyse de données.
Une fonction de fenêtre effectue un calcul sur un ensemble de lignes de table qui sont d'une manière ou d'une autre liées à la ligne actuelle. Cet ensemble de lignes est appelé une "fenêtre" ou "cadre de fenêtre". La différence clé avec les fonctions d'agrégation classiques est que les fonctions de fenêtre ne regroupent pas les lignes en une seule ligne de sortie—chaque ligne conserve son identité.
Imaginez que vous regardez à travers une fenêtre mobile pendant que vous parcourez vos données. Pour chaque ligne, vous pouvez voir et calculer des valeurs basées sur les lignes associées autour d'elle, mais chaque ligne apparaît toujours séparément dans le résultat.
Caractéristiques clés :
OVERLa syntaxe générale d'une fonction de fenêtre est :
nom_fonction_fenetre(expression) OVER (
[PARTITION BY expression_partition]
[ORDER BY expression_tri]
[clause_cadre_fenetre]
)
Composants :
ROW_NUMBER, SUM, AVG)Commençons par l'une des fonctions de fenêtre les plus couramment utilisées : ROW_NUMBER(). Cette fonction attribue un numéro séquentiel unique à chaque ligne dans une partition.
SELECT
payment_id,
customer_id,
amount,
payment_date,
ROW_NUMBER() OVER (ORDER BY payment_date) AS row_num
FROM
payment
LIMIT 10;
Cette requête attribue un numéro séquentiel à chaque paiement ordonné par date de paiement. La clause OVER (ORDER BY payment_date) indique à SQL de :
payment_dateLe véritable pouvoir des fonctions de fenêtre apparaît lorsque vous utilisez PARTITION BY pour créer des fenêtres séparées pour différents groupes :
SELECT
customer_id,
amount,
payment_date,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY payment_date
) AS payment_number
FROM
payment
WHERE
customer_id IN (1, 2, 3)
ORDER BY
customer_id,
payment_date;
Voici ce qui se passe :
PARTITION BY customer_id crée une fenêtre séparée pour chaque clientpayment_dateROW_NUMBER() commence à compter à partir de 1 pour chaque nouveau clientVisualisation :
Client 1 : Client 2 : Client 3 :
Ligne 1 ----\ Ligne 1 ----\ Ligne 1 ----\
Ligne 2 -----\ Ligne 2 -----\ Ligne 2 -----\
Ligne 3 ------\ Ligne 3 ------\ Ligne 3 ------\
... ... ...
Chaque client a sa propre numérotation de lignes indépendante.
Les fonctions de fenêtre facilitent l'identification de l'enregistrement le plus récent dans chaque groupe :
WITH numbered_payments AS (
SELECT
customer_id,
amount,
payment_date,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY payment_date DESC
) AS recency_rank
FROM
payment
)
SELECT
customer_id,
amount,
payment_date
FROM
numbered_payments
WHERE
recency_rank = 1
ORDER BY
customer_id
LIMIT 10;
Cette requête trouve le paiement le plus récent pour chaque client en :
recency_rank = 1 (le plus récent)Les fonctions de fenêtre peuvent également effectuer des agrégations tout en conservant les lignes individuelles :
SELECT
customer_id,
amount,
payment_date,
SUM(amount) OVER (PARTITION BY customer_id) AS total_spent,
AVG(amount) OVER (PARTITION BY customer_id) AS avg_payment,
amount - AVG(amount) OVER (PARTITION BY customer_id) AS diff_from_avg
FROM
payment
WHERE
customer_id IN (1, 2, 3)
ORDER BY
customer_id,
payment_date;
Pour chaque paiement, cette requête montre :
Remarquez comment les fonctions d'agrégation classiques nécessiteraient un GROUP BY et regrouperaient les lignes, mais les fonctions de fenêtre vous permettent de conserver tous les détails tout en ajoutant un contexte agrégé.
Il est important de comprendre la différence :
GROUP BY (Fonctions d'agrégation) :
SELECT
customer_id,
COUNT(*) AS payment_count,
SUM(amount) AS total_amount
FROM
payment
GROUP BY
customer_id;
Résultat : Une ligne par client
Fonctions de fenêtre :
SELECT
customer_id,
payment_id,
amount,
COUNT(*) OVER (PARTITION BY customer_id) AS payment_count,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM
payment;
Résultat : Chaque ligne de paiement préservée, avec des valeurs agrégées ajoutées comme colonnes supplémentaires
ROW_NUMBER()).GROUP BY, les fonctions de fenêtre ne regroupent pas les lignes—elles ajoutent des colonnes calculées à vos données existantes.Dans les prochaines leçons, nous explorerons d'autres fonctions de fenêtre comme RANK(), DENSE_RANK(), NTILE(), et approfondirons les cadres de fenêtre et les calculs analytiques avancés.